 #include "os_cfg.h"

    .text
    .extern kernel_init
    .extern init_main
    .global _start

_start:
    mov 0x04(%esp), %eax    // 从栈帧中取出调用者压入的参数 &boot_info
    push %eax               // 调用kernel_init函数，压入参数 &boot_info
    call kernel_init

    jmp $KERNEL_SELECTOR_CS, $gdt_reload
gdt_reload:
	mov $KERNEL_SELECTOR_DS, %ax
	mov %ax, %ds
	mov %ax, %es
	mov %ax, %ss
	mov %ax, %fs
	mov %ax, %gs
    mov $(stack + KERNEL_STACK_SIZE), %esp
    jmp init_main

    .bss
.comm stack, KERNEL_STACK_SIZE

    .text
.macro exception_handler name num with_err_code
    .global exception_handler_\name
    .extern do_handler_\name

exception_handler_\name:
    // 如果没有err_code，则手动压入一个0
    .if \with_err_code == 0
        push $0
    .endif
    push $\num  // 压入中断向量号
    pusha
    push %ds
    push %es
    push %fs
    push %gs

    push %esp   // 模拟__cdecl调用，压入当前栈指针，指向中断发生后的栈信息
    call do_handler_\name
    add $4, %esp    // 清理参数空间

    pop %gs
    pop %fs
    pop %es
    pop %ds
    popa
    add $8, %esp
    iret

.endm

exception_handler unknown, -1, 0
exception_handler divider, 0, 0
exception_handler Debug, 1, 0
exception_handler NMI, 2, 0
exception_handler breakpoint, 3, 0
exception_handler overflow, 4, 0
exception_handler bound_range, 5, 0
exception_handler invalid_opcode, 6, 0
exception_handler device_unavailable, 7, 0
exception_handler double_fault, 8, 1
exception_handler invalid_tss, 10, 1
exception_handler segment_not_present, 11, 1
exception_handler stack_segment_fault, 12, 1
exception_handler general_protection, 13, 1
exception_handler page_fault, 14, 1
exception_handler fpu_error, 16, 0
exception_handler alignment_check, 17, 1
exception_handler machine_check, 18, 0
exception_handler smd_exception, 19, 0
exception_handler virtual_exception, 20, 0
exception_handler control_exception, 21, 0

// 硬件中断
exception_handler timer, 0x20, 0
//exception_handler kbd, 0x21, 0
//exception_handler ide_primary, 0x2E, 0


    .text
    .global simple_switch
    
// void simple_switch(uint32_t **from_esp, uint32_t *to_esp);
simple_switch:
    //%ebp, %ebx, %edi, %esi, %esp属于调用函数，
    //被调用的函数必须为其调用者保留这些寄存器的值。
    push %ebp
    mov %esp, %ebp
    push %ebx
    push %esi
    push %edi

    /*
     * 栈帧结构：
     *  参数 to_esp     ebp + 0x0c
     *  参数 from_esp   ebp + 0x08
     *  caller 返回地址 ebp + 0x04
     *  caller ebp      ebp + 0x00
     */
    mov 0x08(%ebp), %eax    //取出参数from
    mov %esp, (%eax)        //保存当前栈到task_t.stack中
    mov 0x0c(%ebp), %edx    //取出参数to
    mov %edx, %esp          //切换到新任务的栈

    pop %edi
    pop %esi
    pop %ebx
    // mov %ebp, %esp   上面已经恢复新任务的esp，故此处无需再恢复esp
    pop %ebp
    ret